package com.xc.file.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.xc.core.bean.QueryBean;
import com.xc.core.utils.ServiceUtils;
import com.xc.file.bean.*;
import com.xc.file.config.Constants;
import com.xc.file.dto.FileDto;
import com.xc.file.dto.FolderDto;
import com.xc.file.dto.FolderFileDto;
import com.xc.file.dto.UploadDto;
import com.xc.file.entity.FileEntity;
import com.xc.file.entity.FileHashEntity;
import com.xc.file.entity.FolderEntity;
import com.xc.file.enums.FailCode;
import com.xc.file.enums.FileSuffix;
import com.xc.file.mapper.FileHashMapper;
import com.xc.file.mapper.FileMapper;
import com.xc.file.mapper.FolderMapper;
import com.xc.file.model.CrossPointModel;
import com.xc.file.model.ShareIdModel;
import com.xc.file.model.SubdirectoryModel;
import com.xc.file.service.*;
import com.xc.tool.utils.FileUtils;
import com.xc.tool.utils.Md5Utils;
import com.xc.tool.utils.ObjectUtils;
import com.xc.tool.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.io.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * <p>文件夹服务实现类</p>
 *
 * @author xc
 * @version v1.0
 */
@Service
@Slf4j
public class FolderServiceImpl extends ServiceImpl<FolderMapper, FolderEntity> implements FolderService {

    @Autowired
    private FolderMapper folderMapper;
    @Autowired
    private FileService fileService;
    @Autowired
    private FileMapper fileMapper;
    @Autowired
    private Constants constants;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private UploadService uploadService;
    @Autowired
    private ShareService shareService;
    @Autowired
    private FileCacheService fileCacheService;
    @Autowired
    private FileHashMapper fileHashMapper;
    @Autowired
    private UserInfoService userInfoService;

    @Override
    public FolderDto createFolder(String userId, String parentId, String folderName) {
        FolderEntity folderEntity = new FolderEntity();
        folderEntity.setParentId(parentId);
        folderEntity.setName(folderName);
        folderEntity.setUserId(userId);
        FolderEntity entity = folderMapper.selectOne(new QueryWrapper<>(folderEntity));
        if (entity != null) {
            //不等于空，重命名文件
            String name = FileUtils.rename(entity.getName());
            folderEntity.setName(name);
        }
        if (!this.retBool(folderMapper.insert(folderEntity))) {
            throw FailCode.CREATE_FOLDER_FAIL.getOperateException();
        }
        return ObjectUtils.convert(new FolderDto(), folderEntity);
    }

    @Override
    public String createFolder(String[] folderPaths, int index, String userId, String parentId) {
        synchronized ("") {
            if (folderPaths.length <= index) {
                return parentId;
            }
            String folderName = folderPaths[index];
            FolderEntity folderEntity = new FolderEntity();
            folderEntity.setUserId(userId);
            folderEntity.setName(folderName);
            folderEntity.setParentId(parentId);
            FolderEntity entity = folderMapper.selectOne(new QueryWrapper<>(folderEntity));
            if (entity == null) {
                if (!this.retBool(folderMapper.insert(folderEntity))) {
                    throw FailCode.CREATE_FOLDER_FAIL.getOperateException();
                }
                index++;
                return this.createFolder(folderPaths, index, userId, folderEntity.getId());
            } else {
                index++;
                return this.createFolder(folderPaths, index, userId, entity.getId());
            }
        }
    }


    @Override
    public FolderDto updateFolder(String userId, String id, UpdateFolderBean updateFolderBean) {
        FolderEntity folderEntity = folderMapper.selectById(id);
        if (folderEntity == null) {
            throw FailCode.FOLDER_NOT_EXIST.getOperateException();
        }
        if (!folderEntity.getUserId().equals(userId)) {
            throw FailCode.NOT_OPERATE_AUTHORITY.getOperateException();
        }
        folderEntity.setName(updateFolderBean.getName());
        FolderEntity folder = new FolderEntity();
        folder.setParentId(folderEntity.getParentId());
        folder.setName(folderEntity.getName());
        folder.setUserId(userId);
        FolderEntity entity = folderMapper.selectOne(new QueryWrapper<>(folder));
        if (entity != null && !entity.getId().equals(folderEntity.getId())) {
            throw FailCode.FOLDER_EXIST.getOperateException();
        }
        if (!this.updateById(folderEntity)) {
            throw FailCode.UPDATE_FOLDER_FAIL.getOperateException();
        }
        return ObjectUtils.convert(new FolderDto(), folderEntity);
    }

    @Override
    public List<FolderDto> getUserFolderList(String userId, QueryBean queryBean, FolderBean folderBean) {
        //查询文件夹
        FolderEntity folderEntity = ObjectUtils.convert(new FolderEntity(), folderBean);
        folderEntity.setUserId(userId);
        QueryWrapper<FolderEntity> queryWrapper = ServiceUtils.queryData(queryBean, folderEntity);
        List<FolderEntity> folderEntities = folderMapper.selectList(queryWrapper);
        return ObjectUtils.convertList(folderEntities, FolderDto.class);
    }

    @Override
    @Transactional
    public void deleteUserFolder(String userId, String folderId) {
        //获取下级文件夹及文件
        List<FolderEntity> folders = new ArrayList<>();
        //获取文件夹信息
        FolderEntity folderEntity = folderMapper.selectById(folderId);
        //验证文件夹信息是否存在
        if (folderEntity == null) {
            throw FailCode.FOLDER_NOT_EXIST.getOperateException();
        }
        //验证是否有操作权限
        if (!folderEntity.getUserId().equals(userId)) {
            throw FailCode.NOT_OPERATE_AUTHORITY.getOperateException();
        }
        folders.add(folderEntity);
        //查询文件夹下文件
        FileEntity fileEntity = new FileEntity();
        fileEntity.setFolderId(folderEntity.getId());
        List<FileEntity> files = fileMapper.selectList(new QueryWrapper<>(fileEntity));
        int index = 0;
        while (index < folders.size()) {
            FolderEntity folder = new FolderEntity();
            folder.setParentId(folders.get(index).getId());
            List<FolderEntity> folderList = folderMapper.selectList(new QueryWrapper<>(folder));
            for (FolderEntity folderEntity1 : folderList) {
                FileEntity file = new FileEntity();
                file.setFolderId(folderEntity1.getId());
                files.addAll(fileMapper.selectList(new QueryWrapper<>(file)));
            }
            folders.addAll(folderList);
            index++;
        }
        // 删除文件
        List<String> fileIds = new ArrayList<>();
        for (FileEntity file : files) {
            fileIds.add(file.getId());
        }
        if (fileIds.size() > 0) {
            QueryWrapper<FileEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("id", fileIds);
            if (!SqlHelper.retBool(fileMapper.delete(queryWrapper))) {
                throw FailCode.DELETE_FILE_FAIL.getOperateException();
            }
        }
        // 删除文件夹
        List<String> folderIds = new ArrayList<>();
        for (FolderEntity folder : folders) {
            folderIds.add(folder.getId());
        }
        if (folderIds.size() > 0) {
            QueryWrapper<FolderEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("id", folderIds);
            if (!SqlHelper.retBool(folderMapper.delete(queryWrapper))) {
                throw FailCode.DELETE_FOLDER_FAIL.getOperateException();
            }
        }
    }

    @Override
    @Transactional
    public FolderFileDto batchCopyFolderFile(String userId, String folderId, FolderFileBean folderFileBean) {
        FolderFileDto folderFileDto = new FolderFileDto();
        long size = 0;
        //计算出目录的大小
        size += getFoldersSize(userId, folderFileBean.getFolderIds(), null);
        // 查询根目录文件的大小
        size += fileService.getFileSize(folderFileBean.getFileIds(), userId);
        // 验证文件大小是否存的下
        userInfoService.verifyUserSpace(userId, size);
        //复制文件
        fileService.batchCopyFile(userId, folderId, folderFileBean.getFileIds(), true);
        //文件夹复制
        folderFileDto.setFolders(verifyBatchCopyFolder(folderFileBean.getFolderIds(), folderId, userId, null, true));
        return folderFileDto;
    }

    @Override
    @Transactional
    public FolderFileDto saveShareFolderFile(String userId, String folderId, String shareId, FolderFileBean folderFileBean) {
        FolderFileDto folderFileDto = new FolderFileDto();
        // 获取共享的文件夹/文件信息
        ShareIdModel shareIdModel = shareService.getShareIdModelByShareId(shareId);
        // 获取需要保存的根文件id
        List<String> rootFileIds = new ArrayList<>();
        for (String rootFileId : shareIdModel.getRootFileIds()) {
            for (String fileId : folderFileBean.getFileIds()) {
                if (rootFileId.equals(fileId)) {
                    rootFileIds.add(rootFileId);
                }
            }
        }
        // 获取需要保存的根文件夹id
        List<String> rootFolderIds = new ArrayList<>();
        for (String rootFolderId : shareIdModel.getRootFolderIds()) {
            for (String id : folderFileBean.getFolderIds()) {
                if (rootFolderId.equals(id)) {
                    rootFolderIds.add(id);
                }
            }
        }
        long size = 0;
        //计算出目录的大小
        size += getFoldersSize(null, rootFolderIds, shareIdModel.getFileIds());
        // 查询根目录文件的大小
        size += fileService.getFileSize(rootFileIds, null);
        // 验证文件大小是否存的下
        userInfoService.verifyUserSpace(userId, size);
        // 复制文件
        folderFileDto.setFiles(fileService.batchCopyFile(userId, folderId, rootFileIds, false));
        // 复制文件夹
        folderFileDto.setFolders(verifyBatchCopyFolder(folderFileBean.getFolderIds(), folderId, userId, shareIdModel, false));
        return folderFileDto;
    }

    /**
     * 验证批量复制目录的信息
     *
     * @param folderIds    待复制的目录id集合
     * @param folderId     新目录id
     * @param userId       用户id
     * @param shareIdModel 共享信息
     * @param isCopy       是否是拷贝
     * @return 文件夹信息集合
     */
    private List<FolderDto> verifyBatchCopyFolder(List<String> folderIds, String folderId, String userId, ShareIdModel shareIdModel, boolean isCopy) {
        List<FolderDto> folderDtoList = new ArrayList<>();
        if (folderIds.size() > 0) {
            QueryWrapper<FolderEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("id", folderIds);
            List<FolderEntity> folderList = folderMapper.selectList(queryWrapper);
            if (isCopy) {
                // 验证目录是不是当前用户的
                for (FolderEntity folderEntity : folderList) {
                    if (!folderEntity.getUserId().equals(userId)) {
                        throw FailCode.NOT_OPERATE_AUTHORITY.getOperateException();
                    }
                }
            }
            // 获取新文件夹下文件
            FolderEntity folder = new FolderEntity();
            folder.setParentId(folderId);
            List<FolderEntity> folderEntities = folderMapper.selectList(new QueryWrapper<>(folder));
            for (FolderEntity folderEntity : folderEntities) {
                //  验证文件是否重复
                for (FolderEntity folderEntity1 : folderList) {
                    if (folderEntity1.getName().equals(folderEntity.getName())) {
                        if (isCopy) {
                            throw FailCode.FOLDER_EXIST.getOperateException();
                        } else {
                            String name = FileUtils.rename(folderEntity1.getName());
                            folderEntity1.setName(name);
                        }
                    }
                }
            }
            // 获取新目录的所有上级目录
            List<FolderEntity> entityList = getParentFolders(userId, folderId);
            for (FolderEntity folderEntity1 : folderList) {
                for (FolderEntity folderEntity : entityList) {
                    if (folderEntity.getId().equals(folderEntity1.getId())) {
                        throw FailCode.CAN_NO_TOWARDS_LOWER_LEVEL_COPY.getOperateException();
                    }
                }
                folderEntity1.setParentId(folderId);
                folderEntity1.setUserId(userId);
            }
            if (isCopy) {
                folderDtoList = batchCopyFolder(folderList, null);
            } else {
                folderDtoList = batchCopyFolder(folderList, shareIdModel);
            }
        }
        return folderDtoList;
    }

    /**
     * 批量复制目录
     *
     * @param entities     需要复制的目录集合
     * @param shareIdModel 共享信息
     * @return 文件夹信息集合
     */
    private List<FolderDto> batchCopyFolder(List<FolderEntity> entities, ShareIdModel shareIdModel) {
        List<FolderDto> folders = new ArrayList<>();
        // 向上获取父级的所有目录
        for (FolderEntity folderEntity : entities) {
            String parentId = folderEntity.getId();
            folderEntity.setId(null);
            folderEntity.setUpdateTime(null);
            folderEntity.setVersion(null);
            folderEntity.setCreateTime(null);
            folderEntity.setUserId(folderEntity.getUserId());
            folderEntity.setParentId(folderEntity.getParentId());
            if (!SqlHelper.retBool(folderMapper.insert(folderEntity))) {
                throw FailCode.CREATE_FOLDER_FAIL.getOperateException();
            }
            //复制文件及以下文件夹
            subdirectoryHandle(parentId, folderEntity.getId(), (subdirectoryInfo) -> {
                if (subdirectoryInfo.getIsFile()) {
                    List<FileEntity> files = subdirectoryInfo.getFiles();
                    for (FileEntity fileEntity : files) {
                        fileEntity.setUpdateTime(null);
                        fileEntity.setCreateTime(null);
                        fileEntity.setVersion(null);
                        fileEntity.setUserId(folderEntity.getUserId());
                        fileEntity.setFolderId(subdirectoryInfo.getNewParentId());
                        if (shareIdModel == null) {
                            //复制文件
                            fileEntity.setId(null);
                            if (!SqlHelper.retBool(fileMapper.insert(fileEntity))) {
                                throw FailCode.CREATE_FILE_FAIL.getOperateException();
                            }
                        } else {
                            for (String fileId : shareIdModel.getFileIds()) {
                                if (fileId.equals(fileEntity.getId())) {
                                    //复制文件
                                    fileEntity.setId(null);
                                    if (!SqlHelper.retBool(fileMapper.insert(fileEntity))) {
                                        throw FailCode.CREATE_FILE_FAIL.getOperateException();
                                    }
                                }
                            }
                        }
                    }
                } else {
                    FolderEntity folder = subdirectoryInfo.getFolder();
                    folder.setUpdateTime(null);
                    folder.setCreateTime(null);
                    folder.setVersion(null);
                    folder.setUserId(folderEntity.getUserId());
                    folder.setParentId(subdirectoryInfo.getNewParentId());
                    if (shareIdModel == null) {
                        //复制文件夹
                        folder.setId(null);
                        if (!SqlHelper.retBool(folderMapper.insert(folder))) {
                            throw FailCode.CREATE_FOLDER_FAIL.getOperateException();
                        }
                    } else {
                        for (String folderId : shareIdModel.getFolderIds()) {
                            if (folderId.equals(folder.getId())) {
                                //复制文件夹
                                folder.setId(null);
                                if (!SqlHelper.retBool(folderMapper.insert(folder))) {
                                    throw FailCode.CREATE_FOLDER_FAIL.getOperateException();
                                }
                            }
                        }
                    }
                }
            });
            folders.add(ObjectUtils.convert(new FolderDto(), folderEntity));
        }
        return folders;
    }

    @Override
    @Transactional
    public List<FolderDto> updateUserFolderList(String userId, String parentId, List<String> ids) {
        List<FolderDto> folders = new ArrayList<>();
        //向上获取父级的所有目录
        List<FolderEntity> entities1 = getParentFolders(userId, parentId);
        for (String id : ids) {
            for (FolderEntity entity : entities1) {
                if (entity.getId().equals(id)) {
                    throw FailCode.CAN_NO_TOWARDS_LOWER_LEVEL_MOVE.getOperateException();
                }
            }
            //移动文件夹
            FolderEntity folderEntity = folderMapper.selectById(id);
            if (!folderEntity.getUserId().equals(userId)) {
                throw FailCode.NOT_OPERATE_AUTHORITY.getOperateException();
            }
            FolderEntity entity = new FolderEntity();
            entity.setUserId(userId);
            entity.setParentId(parentId);
            entity.setName(folderEntity.getName());
            entity = folderMapper.selectOne(new QueryWrapper<>(entity));
            if (entity != null) {
                throw FailCode.FOLDER_EXIST.getOperateException();
            }
            folderEntity.setParentId(parentId);
            folderEntity.setUpdateTime(null);
            //修改文件夹
            if (!SqlHelper.retBool(folderMapper.updateById(folderEntity))) {
                throw FailCode.UPDATE_FOLDER_FAIL.getOperateException();
            }
            folders.add(ObjectUtils.convert(new FolderDto(), folderEntity));
        }
        return folders;
    }

    @Override
    public List<FolderEntity> getParentFolders(String userId, String folderId) {
        List<FolderEntity> folders = new ArrayList<>();
        while (true) {
            FolderEntity folder = new FolderEntity();
            folder.setId(folderId);
            folder.setUserId(userId);
            FolderEntity folderEntity = folderMapper.selectOne(new QueryWrapper<>(folder));
            if (folderEntity != null) {
                folders.add(folderEntity);
                folderId = folderEntity.getParentId();
            } else {
                break;
            }
        }
        return folders;
    }

    @Override
    public List<FolderEntity> getFoldersByParentId(String parentId) {
        FolderEntity entity = new FolderEntity();
        entity.setParentId(parentId);
        return folderMapper.selectList(new QueryWrapper<>(entity));
    }

    @Override
    public boolean seekFolderCrossPoint(String folderId, String newFolderId, CrossPointModel crossPointModel, Consumer<CrossPointModel> action) {
        //创建内部使用对象
        if (crossPointModel == null) {
            crossPointModel = new CrossPointModel();
            crossPointModel.setFolders(new ArrayList<>());
            crossPointModel.setNewFolders(new ArrayList<>());
        }
        List<FolderEntity> folders = crossPointModel.getFolders();
        List<FolderEntity> newFolders = crossPointModel.getNewFolders();
        boolean bool = false;
        //查询旧的上级文件夹
        FolderEntity folder = null;
        if (folderId != null) {
            folder = folderMapper.selectById(folderId);
            if (folder != null) {
                folders.add(folder);
                bool = true;
            }
        }
        //查询新的上级文件夹
        FolderEntity newFolder = null;
        if (newFolderId != null) {
            newFolder = folderMapper.selectById(newFolderId);
            if (newFolder != null) {
                newFolders.add(newFolder);
                bool = true;
            }
        }
        //判断新旧文件夹是否存在
        if (bool) {
            if (folder == null) {
                //新文件夹存在，递归继续查询上级文件夹
                if (seekFolderCrossPoint(null, newFolder.getParentId(), crossPointModel, action)) {
                    return true;
                }
                if (folders.size() == 0) {
                    action.accept(new CrossPointModel(new ArrayList<>(), newFolders));
                    return true;
                } else {
                    countFolderCrossPoint(folders, newFolders, action);
                    return true;
                }
            } else if (newFolder == null) {
                //旧文件夹存在，递归继续查询上级文件夹
                if (seekFolderCrossPoint(folder.getParentId(), null, crossPointModel, action)) {
                    return true;
                }
                if (newFolders.size() == 0) {
                    action.accept(new CrossPointModel(folders, new ArrayList<>()));
                    return true;
                } else {
                    countFolderCrossPoint(folders, newFolders, action);
                    return true;
                }
            } else {
                //新旧文件夹都存在，递归继续查询上级文件夹
                if (seekFolderCrossPoint(folder.getParentId(), newFolder.getParentId(), crossPointModel, action)) {
                    return true;
                } else {
                    countFolderCrossPoint(folders, newFolders, action);
                    return true;
                }
            }
        } else {
            return false;
        }
    }

    @Override
    public void subdirectoryHandle(String parentId, String newParentId, Consumer<SubdirectoryModel> action) {
        //处理文件
        List<FileEntity> files = fileService.getFilesByFolderId(parentId);
        if (files != null && files.size() != 0) {
            SubdirectoryModel subdirectoryModel = new SubdirectoryModel();
            subdirectoryModel.setIsFile(true);
            subdirectoryModel.setFiles(files);
            subdirectoryModel.setNewParentId(newParentId);
            action.accept(subdirectoryModel);
        }
        //判断是否有下级文件夹，有继续递归出处理
        List<FolderEntity> folders = getFoldersByParentId(parentId);
        if (folders != null) {
            for (FolderEntity folder : folders) {
                SubdirectoryModel subdirectoryModel = new SubdirectoryModel();
                String id = folder.getId();
                subdirectoryModel.setIsFile(false);
                subdirectoryModel.setFolder(folder);
                subdirectoryModel.setNewParentId(newParentId);
                action.accept(subdirectoryModel);
                subdirectoryHandle(id, subdirectoryModel.getFolder().getId(), action);
            }
        }
    }


    @Override
    public String verifyFolder(String folderId, String userId) {
        //验证上级目录是否是根目录
        if (!constants.getRootFolder().equals(folderId)) {
            FolderEntity entity = folderMapper.selectById(folderId);
            //验证父级目录是否存在
            if (entity == null) {
                throw FailCode.PARENT_FOLDER_NOT_EXIST.getOperateException();
            }
            //验证父级目录是不是当前用户的
            if (!entity.getUserId().equals(userId)) {
                throw FailCode.NOT_OPERATE_AUTHORITY.getOperateException();
            }
        } else {
            folderId = constants.getRootFolder();
        }
        return folderId;
    }

    @Override
    public FileDto packFolderFiles(String userId, String folderId, PackFileBean packFileBean, String token) {
        long size = 0;
        //计算出目录的大小
        size += getFoldersSize(userId, packFileBean.getFolderIds(), null);
        // 查询根目录文件的大小
        size += fileService.getFileSize(packFileBean.getFileIds(), userId);
        // 验证文件大小是否存的下
        userInfoService.verifyUserSpace(userId, size);
        //查询文件
        List<FileEntity> fileList = new ArrayList<>();
        if (packFileBean.getFileIds().size() > 0) {
            FileEntity fileEntity = new FileEntity();
            fileEntity.setUserId(userId);
            QueryWrapper<FileEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("id", packFileBean.getFileIds());
            fileList = fileMapper.selectList(queryWrapper);
        }
        //查询文件夹
        List<FolderEntity> folderList = new ArrayList<>();
        if (packFileBean.getFolderIds().size() > 0) {
            FolderEntity folderEntity = new FolderEntity();
            QueryWrapper<FolderEntity> queryWrapper = new QueryWrapper<>(folderEntity);
            queryWrapper.in("id", packFileBean.getFolderIds());
            folderList = folderMapper.selectList(queryWrapper);
        }

        // 检测本服务器空间是否支持打包，不支持调用其他服务器接口打包
        String path = uploadService.getFilePath(size);
        if (path == null) {
            String serviceIp = fileCacheService.getServiceIp(size);
            String url = serviceIp + "/current_user/folder/" + folderId + "/zip_packages";
            HttpHeaders requestHeaders = new HttpHeaders();
            requestHeaders.add("token", token);
            HttpEntity<PackFileBean> requestEntity = new HttpEntity<>(packFileBean, requestHeaders);
            ResponseEntity<FileDto> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, FileDto.class);
            return responseEntity.getBody();
        }
        String fileName = StringUtils.generateOnlyId(constants.getMachineId());
        String tempPath = path + File.separator + fileName + FileSuffix.PACK.getSuffix();
        try (OutputStream outputStream = new FileOutputStream(new File(tempPath));
             CheckedOutputStream cos = new CheckedOutputStream(outputStream, new CRC32());
             ZipOutputStream zipStream = new ZipOutputStream(cos)) {
            // 文件夹处理
            StringBuilder pathBuilder = new StringBuilder();
            for (FolderEntity folderEntity : folderList) {
                pathBuilder.append(folderEntity.getName()).append(File.separator);
                subdirectoryHandle(folderEntity.getId(), null, (subdirectoryInfo) -> {
                    if (subdirectoryInfo.getIsFile()) {
                        List<FileDto> fileDtoList = fileService.setDownloadUrl(ObjectUtils.convertList(subdirectoryInfo.getFiles(), FileDto.class), "/current_user_file/");
                        for (FileDto fileDto : fileDtoList) {
                            try {
                                ZipEntry entry = new ZipEntry(pathBuilder.toString() + fileDto.getName());
                                zipStream.putNextEntry(entry);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            httpDownloadFile(zipStream, fileDto, token);
                        }
                    } else {
                        pathBuilder.append(subdirectoryInfo.getFolder().getName()).append(File.separator);
                        try {
                            ZipEntry entry = new ZipEntry(pathBuilder.toString());
                            zipStream.putNextEntry(entry);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
                ZipEntry entry = new ZipEntry(folderEntity.getName() + File.separator);
                zipStream.putNextEntry(entry);
            }
            // 文件处理
            List<FileDto> fileDtoList = fileService.setDownloadUrl(ObjectUtils.convertList(fileList, FileDto.class), "/current_user_file/");
            for (FileDto fileDto : fileDtoList) {
                ZipEntry entry = new ZipEntry(fileDto.getName());
                zipStream.putNextEntry(entry);
                httpDownloadFile(zipStream, fileDto, token);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 创建文件hash
        File tempFile = new File(tempPath);
        String hashCode = Md5Utils.getFileMd5(tempFile);
        FileHashEntity fileHashEntity = new FileHashEntity();
        fileHashEntity.setSize(tempFile.length());
        fileHashEntity.setHashCode(hashCode);
        fileHashEntity.setServerUrl(constants.getLocalUrl());
        fileHashEntity.setPath(path);
        if (!SqlHelper.retBool(fileHashMapper.insert(fileHashEntity))) {
            throw FailCode.CREATE_FILE_HASH_FAIL.getOperateException();
        }
        //重命名文件
        String newPath = path + File.separator + hashCode + FileSuffix.SUCCESS.getSuffix();
        File newFile = new File(newPath);
        uploadService.rename(tempFile, newFile, hashCode);
        // 上传成功
        UploadDto uploadDto = new UploadDto();
        uploadDto.setFinish(true);
        uploadDto.setHashCode(hashCode);
        FileBean fileBean = new FileBean();
        fileBean.setName(packFileBean.getName() + ".zip");
        fileBean.setHashCode(hashCode);
        fileBean.setSize(fileHashEntity.getSize());
        fileBean.setFolderId(folderId);
        return fileService.createFile(userId, fileBean, false);
    }


    @Override
    public long getUserFolderSize(String userId, String folderId) {
        List<String> folderIds = new ArrayList<>();
        folderIds.add(folderId);
        return getFoldersSize(userId, folderIds, null);
    }

    @Override
    public long getFoldersSize(String userId, List<String> rootFolderIds, List<String> fileIds) {
        long size = 0;
        if (rootFolderIds.size() > 0) {
            List<String> folderIds = new ArrayList<>(rootFolderIds);
            // 查询文件夹下文件夹id
            int index = 0;
            while (index < folderIds.size()) {
                String id = folderIds.get(index);
                FolderEntity folder = new FolderEntity();
                folder.setParentId(id);
                if (userId != null) {
                    folder.setUserId(userId);
                }
                List<FolderEntity> folderList = folderMapper.selectList(new QueryWrapper<>(folder));
                for (FolderEntity folderEntity1 : folderList) {
                    folderIds.add(folderEntity1.getId());
                }
                index++;
            }
            //计算大小
            if (folderIds.size() > 0) {
                QueryWrapper<FileEntity> query = new QueryWrapper<>(new FileEntity());
                query.in("folder_id", folderIds);
                if (fileIds != null && fileIds.size() > 0) {
                    query.in("id", fileIds);
                }
                query.select("sum(size) as total");
                Map<String, Object> map = fileService.getMap(query);
                if (map != null) {
                    size = ((BigDecimal) map.get("total")).longValue();
                }
            }
        }
        return size;
    }

    /**
     * 发送http 请求下载文件打包
     *
     * @param zipStream 打包输出流
     * @param fileDto   文件信息
     */
    private void httpDownloadFile(ZipOutputStream zipStream, FileDto fileDto, String token) {
        String filePath = uploadService.verifyFileExist(fileDto.getHashCode(), FileSuffix.SUCCESS.getSuffix());
        if (filePath == null) {
            restTemplate.execute(fileDto.getUrl(), HttpMethod.GET, clientHttpRequest -> {
                clientHttpRequest.getHeaders().set("token", token);
            }, clientHttpResponse -> {
                try (BufferedInputStream bis = new BufferedInputStream(clientHttpResponse.getBody())) {
                    int count;
                    byte[] bytes = new byte[1024];
                    while ((count = bis.read(bytes, 0, 1024)) != -1) {
                        zipStream.write(bytes, 0, count);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return true;
            });
        } else {
            try (InputStream stream = new FileInputStream(new File(filePath + File.separator + fileDto.getHashCode() + FileSuffix.SUCCESS.getSuffix()));
                 BufferedInputStream bis = new BufferedInputStream(stream)) {
                byte[] bytes = new byte[1024];
                int count;
                while ((count = bis.read(bytes, 0, 1024)) != -1) {
                    zipStream.write(bytes, 0, count);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * <p>计算文件夹交叉点数据</p>
     *
     * @param folders    旧文件夹数据
     * @param newFolders 新目文件夹数据
     * @param action     回调
     */
    private void countFolderCrossPoint(List<FolderEntity> folders, List<FolderEntity> newFolders, Consumer<CrossPointModel> action) {
        int i;
        int j = 0;
        boolean b = false;
        for (i = 0; i < folders.size(); i++) {
            for (j = 0; j < newFolders.size(); j++) {
                if (folders.get(i).getParentId().equals(newFolders.get(j).getParentId())) {
                    b = true;
                    break;
                }
            }
            if (b) {
                break;
            }
        }
        if (b) {
            List<FolderEntity> folderList = new ArrayList<>();
            for (int a = 0; a < i + 1; a++) {
                folderList.add(folders.get(a));
            }
            List<FolderEntity> newFolderList = new ArrayList<>();
            for (int a = 0; a < j + 1; a++) {
                newFolderList.add(newFolders.get(a));
            }
            action.accept(new CrossPointModel(folderList, newFolderList));
        }
    }
}
